<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>密钥资源池 · 总览仪表盘</title>
  <link rel="stylesheet" href="assets/styles.css" />
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-gl@2/dist/echarts-gl.min.js"></script>
<style>
  /* 首页大背景使用动态 GIF，并叠加暗化层保证可读性 */
  body.bigscreen {
     /* 移除缺失的背景图，改用纯色+叠加层 */
     background: #07152b;
   }
  body.bigscreen::before {
    content: '';
    position: fixed; inset: 0;
    background: radial-gradient(transparent, rgba(2,6,23,0.45)) , linear-gradient(to bottom, rgba(2,6,23,0.55), rgba(2,6,23,0.85));
    pointer-events: none;
    z-index: 0;
  }
  .layout, .header, .container { position: relative; z-index: 1; }
  .sidebar { position: relative; z-index: 10; }

  /* 毛玻璃质感卡片（首页模块） */
  .card.glass {
    background: rgba(15, 23, 42, 0.35);
    border: 1px solid rgba(148, 163, 184, 0.18);
    backdrop-filter: blur(12px) saturate(140%);
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    box-shadow: 0 8px 30px rgba(34, 211, 238, 0.08), inset 0 1px 0 rgba(255,255,255,0.06);
    transition: box-shadow .25s ease, transform .25s ease;
  }
  .card.glass:hover {
    box-shadow: 0 10px 36px rgba(34,211,238,0.12), inset 0 1px 0 rgba(255,255,255,0.08);
    transform: translateY(-1px);
  }

  /* 全屏视频背景（不拦截事件） */
  .bg-video {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: -1; /* 位于叠加层之下 */
    pointer-events: none;
    filter: saturate(115%) brightness(0.9);
    background: #07152b; /* 作为视频加载前的底色 */
  }
  /* 关闭特效时隐藏视频背景 */
  .tech-effects-disabled .bg-video { display: none; }
</style>
</head>
<body class="bigscreen datav">
  <header class="header">
    <div class="title datav-title">河北省高速公路联网收费省级密钥资源池管理系统</div>
    <div class="tech-controls">
      <button id="toggleEffects" class="button tech-btn" title="切换科技特效">
        <span class="tech-icon">⚡</span>
      </button>
    </div>
  </header>
  <div class="layout">
    <aside class="sidebar">
      <!-- <div class="logo">密钥资源池</div> -->
      <nav class="menu">
        <a class="active" href="index.html">首页</a>
        <a href="pages/app.html">应用管理</a>
        <a href="pages/crypto.html">加密设备状态</a>
        <a href="pages/security.html">安全设备状态</a>
        <a href="pages/network.html">部省密钥网络状态</a>
        <a href="pages/jobs.html">定时任务</a>
        <!-- <a href="pages/reports.html">报表管理</a> -->
        <div class="tree">
          <div class="tree-node">
            <div class="tree-header">报表管理<span class="chevron"></span></div>
            <div class="tree-children">
              <a class="tree-link" href="pages/reports.html?tab=app" data-tab="app">服务调用统计</a>
              <a class="tree-link" href="pages/reports.html?tab=crypto" data-tab="crypto">加密设备运行监测</a>
              <a class="tree-link" href="pages/reports.html?tab=security" data-tab="security">安全设备运行监测</a>
              <a class="tree-link" href="pages/reports.html?tab=network" data-tab="network">部省密钥网络运行报表</a>
            </div>
          </div>
        </div>
      </nav>
      
      
    </aside>
    <div class="content">
      <main class="container">
    <section class="grid cols-4">
      <div class="card glass datav success">
        <h3 class="panel-title"><span class="dot"></span> 接口调用成功率 <span class="bar"></span></h3>
        <div class="value" id="metric-success-rate">99.96%</div>
        <div class="hint">近 1 小时</div>
      </div>
      <div class="card glass datav success">
        <h3 class="panel-title"><span class="dot"></span> 加密设备在线数 <span class="bar"></span></h3>
        <div class="value" id="metric-crypto-online">—/— 台</div>
        <div class="hint">在线/总数</div>
      </div>
      <div class="card glass datav success">
        <h3 class="panel-title"><span class="dot"></span> 安全设备在线数 <span class="bar"></span></h3>
        <div class="value" id="metric-security-online">—/— 台</div>
        <div class="hint">在线/总数</div>
      </div>
      <div class="card glass datav success">
        <h3 class="panel-title"><span class="dot"></span> 网络连通率 <span class="bar"></span></h3>
        <div class="value" id="metric-network">100.00%</div>
        <div class="hint">近 1 小时</div>
      </div>

    </section>

    <!-- 上排：趋势图单独占一行全宽 -->
    <section class="card glass datav" style="margin-top:16px;">
      <h3 class="panel-title"><span class="dot"></span> 最近 12 小时接口调用趋势 <span class="bar"></span></h3>
      <div class="chart-box" style="height: 400px;"><div id="chartTrend" style="width:100%;height:100%;"></div></div>
    </section>

    <!-- 下排：并排两图（各模块调用数量、今日TOP10） -->
    <section class="grid cols-2" style="margin-top:16px;">
      <div class="card glass datav">
        <div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
          <h3 class="panel-title" style="margin:0"><span class="dot"></span> 各模块调用数量 <span class="bar"></span></h3>
          <div id="moduleTabs" style="display:flex; gap:8px;">
            <button class="button success" data-period="day">小时</button>
            <button class="button secondary" data-period="week">天</button>
            <button class="button secondary" data-period="month">周</button>
          </div>
        </div>
        <div class="chart-box" style="height: 340px;"><div id="chartModules" style="width:100%;height:100%;"></div></div>
      </div>
      <div class="card glass datav">
          <div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">
            <h3 class="panel-title" style="margin:0"><span class="dot"></span> 今日调用次数 TOP10 接口 <span class="bar"></span></h3>
            <div class="hint">含接口热度指数雷达</div>
          </div>
          <div class="chart-box" style="height: 160px;"><div id="chartHeatRadar" style="width:100%;height:100%;"></div></div>
          <div class="chart-box" style="height: 340px;"><div id="chartTop10" style="width:100%;height:100%;"></div></div>
        </div>
    </section>

    <!-- 底部全宽：数据清理提示与手动清理按钮 -->
    <section class="card glass" style="margin-top:16px;">
      <h3 class="panel-title"><span class="dot"></span> 数据清理提示 <span class="bar"></span></h3>
      <div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;">
        <div>
          <div>当前留存周期：<strong id="retention-days">7 天</strong> ,下次自动清理：<span id="next-clean">2025-10-27 02:00</span></div>
          <div class="hint">关键操作需二次确认，完成后会出现反馈提示。</div>
        </div>
        <button class="button warning" id="btnClean">手动清理</button>
      </div>
    </section>
      </main>
    </div>
  </div>

  <script>
    // 注册霓虹深蓝主题（文本与指示线统一）
    echarts.registerTheme('neon-dark', {
      backgroundColor: 'transparent',
      textStyle: { color: '#cbd5e1', fontFamily: 'ui-sans-serif, system-ui, Segoe UI, Microsoft YaHei, sans-serif' },
      axisPointer: { lineStyle: { color: '#22d3ee' } }
    });

    // 顶部数字仪表盘数值跳动动画
    function animateNumber(el, target, suffix = '%', duration = 1200) {
      if (!el) return;
      const start = 0; const startTime = performance.now();
      function step(t) {
        const p = Math.min((t - startTime) / duration, 1);
        const val = Math.round((start + (target - start) * p) * 100) / 100;
        el.textContent = val.toFixed(2) + suffix;
        if (p < 1) requestAnimationFrame(step);
      }
      requestAnimationFrame(step);
    }
    animateNumber(document.getElementById('metric-success-rate'), 99.96);
    animateNumber(document.getElementById('metric-network'), 100.00);

    // 趋势图：双轴动态折线 + 时间轴缩放
    const trendEl = document.getElementById('chartTrend');
    const trendChart = echarts.init(trendEl, 'neon-dark', { renderer: 'canvas' });
    function getLastHours(count) {
      const now = new Date();
      const arr = [];
      for (let i = count - 1; i >= 0; i--) {
        const d = new Date(now.getTime() - i * 3600000);
        arr.push(`${d.getHours()}时`);
      }
      return arr;
    }
    let trendLabels = getLastHours(12);
    let trendSeries1 = trendLabels.map(() => Math.floor(500 + Math.random() * 300));
    let trendSeries2 = trendLabels.map(() => +(99 + Math.random()).toFixed(2));
    trendChart.setOption({
      grid: { left: 40, right: 60, top: 40, bottom: 40 },
      tooltip: { trigger: 'axis' },
      legend: { textStyle: { color: '#e5e7eb' } },
      xAxis: { type: 'category', data: trendLabels, axisLabel: { color: '#cbd5e1' }, axisLine: { lineStyle: { color: '#334155' } } },
      yAxis: [
        { type: 'value', axisLabel: { color: '#cbd5e1' }, splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } } },
        { type: 'value', min: 0, max: 100, axisLabel: { color: '#cbd5e1' }, splitLine: { show: false } }
      ],
      dataZoom: [ { type: 'slider', xAxisIndex: 0, realtime: true, textStyle: { color: '#94a3b8' } }, { type: 'inside', xAxisIndex: 0 } ],
      series: [
        { name: '调用总量', type: 'line', data: trendSeries1, smooth: true, lineStyle: { color: '#0ea5e9' }, areaStyle: { color: 'rgba(14,165,233,0.18)' } },
        { name: '成功率(%)', type: 'line', yAxisIndex: 1, data: trendSeries2, smooth: true, lineStyle: { color: '#10b981' }, areaStyle: { color: 'rgba(16,185,129,0.10)' } }
      ]
    });
    // 动态更新：在同一小时内仅刷新最后一个点，避免横坐标重复
    setInterval(() => {
      const curLabel = `${new Date().getHours()}时`;
      const lastLabel = trendLabels[trendLabels.length - 1];
      const newVal1 = Math.floor(500 + Math.random() * 300);
      const newVal2 = +(99 + Math.random()).toFixed(2);
      if (curLabel === lastLabel) {
        // 同一小时：只更新最后一个数据点
        trendSeries1[trendSeries1.length - 1] = newVal1;
        trendSeries2[trendSeries2.length - 1] = newVal2;
        trendChart.setOption({ series: [{ data: trendSeries1 }, { data: trendSeries2 }] });
      } else {
        // 跨小时：推进窗口并追加新的小时标签
        trendLabels.shift();
        trendLabels.push(curLabel);
        trendSeries1.shift();
        trendSeries1.push(newVal1);
        trendSeries2.shift();
        trendSeries2.push(newVal2);
        trendChart.setOption({ xAxis: { data: trendLabels }, series: [{ data: trendSeries1 }, { data: trendSeries2 }] });
      }
    }, 2500);
    window.addEventListener('resize', () => trendChart.resize());
    trendChart.on('click', (p) => { /* TODO: 点击穿透详情 */ });

    // 模块 立体渐变柱状图（2D pictorialBar 风格，保留切换）
    const MODULE_LABELS = ['应用管理', '加密设备', '安全设备', '部省网络'];
    const MODULE_DATA = { day: [31167, 6051, 2761, 1800], week: [7000, 5200, 4300, 4100], month: [30000, 21000, 19000, 17000] };
    const modulesEl = document.getElementById('chartModules');
    const modulesChart = echarts.init(modulesEl, 'neon-dark');
    const fmt = (n) => (n||0).toLocaleString('zh-CN');
    function buildNeonBar(period) {
      const list = MODULE_DATA[period];
      return {
        grid: { left: 60, right: 20, top: 40, bottom: 40 },
        tooltip: { trigger: 'item', formatter: (p) => `${MODULE_LABELS[p.dataIndex]}<br/>${fmt(p.value)} 次` },
        xAxis: { type: 'category', data: MODULE_LABELS, axisLabel: { color: '#cbd5e1' }, axisLine: { lineStyle: { color: '#1f2937' } } },
        yAxis: { type: 'value', name: '次', nameTextStyle: { color: '#93c5fd' }, axisLabel: { color: '#cbd5e1', formatter: (v) => fmt(v) }, splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } } },
        series: [
          {
            name: 'main', type: 'bar', data: list, barWidth: 28,
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: '#a5f3fc' },
                { offset: 0.25, color: '#22d3ee' },
                { offset: 1, color: '#0ea5e9' }
              ]),
              barBorderRadius: [9, 9, 2, 2],
              shadowColor: '#22d3ee', shadowBlur: 10
            },
            label: { show: true, position: 'top', color: '#e5e7eb', formatter: (p) => fmt(p.value) }
          },
          {
            // 中央亮带（流光）
            name: 'glow', type: 'bar', data: list, barWidth: 8, barGap: '-100%', z: 10, silent: true,
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: '#a5f3fc' },
                { offset: 0.7, color: '#14b8a6' },
                { offset: 1, color: 'rgba(20,184,166,0.15)' }
              ]),
              barBorderRadius: [6, 6, 0, 0]
            }
          },
          {
            // 顶部菱形高光盖帽
            type: 'pictorialBar', symbol: 'diamond', z: 12, symbolSize: [28, 10], symbolOffset: [0, -6],
            data: list, itemStyle: { color: '#22d3ee' }
          }
        ]
      };
    }
    let cur = 'day';
    modulesChart.setOption(buildNeonBar(cur));
    const tabs = document.getElementById('moduleTabs');
    tabs?.addEventListener('click', (e) => {
      const btn = e.target.closest('button[data-period]'); if (!btn) return;
      cur = btn.dataset.period; modulesChart.setOption(buildNeonBar(cur), true);
      [...tabs.querySelectorAll('button')].forEach(b => { b.classList.remove('success'); b.classList.add('secondary'); });
      btn.classList.remove('secondary'); btn.classList.add('success');
    });
    window.addEventListener('resize', () => modulesChart.resize());

    // 右上：接口热度指数雷达
    const radarEl = document.getElementById('chartHeatRadar');
    const radarChart = echarts.init(radarEl, 'neon-dark');
    const radarIndicators = [
      { name: '成功率', max: 100 }, { name: '平均延迟', max: 500 }, { name: '错误率', max: 10 }, { name: '吞吐量', max: 1000 }, { name: '稳定性', max: 100 }
    ];
    const radarData = [96, 120, 2, 780, 92];
    radarChart.setOption({
      tooltip: {},
      radar: { indicator: radarIndicators, axisName: { color: '#93c5fd' }, splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } }, splitArea: { areaStyle: { color: ['rgba(14,165,233,0.05)'] } } },
      series: [{ type: 'radar', data: [{ value: radarData, name: '接口热度指数', areaStyle: { color: 'rgba(14,165,233,0.25)' }, lineStyle: { color: '#0ea5e9' }, itemStyle: { color: '#0ea5e9' } }] }]
    });
    window.addEventListener('resize', () => radarChart.resize());

    // 右下：横向流光柱状图（实时重排）
    const top10El = document.getElementById('chartTop10');
    const top10Chart = echarts.init(top10El, 'neon-dark');
    let labelsTop10 = [
      'CPU卡一发获取业务单据号',
      'CPU卡一发更新密钥',
      'CPU卡一发更新0015文件',
      'CPU卡一发上送发行结果',
      'CPU卡二发获取业务单据号',
      'CPU用户卡0016文件更新',
      'CPU用户卡0015文件更新',
      'CPU卡发行结果上送',
      'CPU卡修改车辆信息申请',
      'CPU卡修改有效期申请'
    ];
    let valuesTop10 = labelsTop10.map(() => Math.floor(50 + Math.random() * 150));
    function renderTop10() {
      const paired = labelsTop10.map((l, i) => ({ name: l, value: valuesTop10[i] }));
      paired.sort((a, b) => b.value - a.value);
      top10Chart.setOption({
        grid: { left: 240, right: 40, top: 20, bottom: 20 },
        xAxis: { type: 'value', axisLabel: { color: '#cbd5e1' }, splitLine: { lineStyle: { color: 'rgba(255,255,255,0.06)' } } },
        yAxis: { type: 'category', inverse: true, axisLabel: { color: '#cbd5e1' }, data: paired.map(p => p.name) },
        tooltip: { trigger: 'item' },
        series: [{
          type: 'bar',
          data: paired.map(p => p.value),
          barWidth: 16,
          itemStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
              { offset: 0, color: '#0ea5e9' }, { offset: .6, color: '#22d3ee' }, { offset: 1, color: '#a5f3fc' }
            ]),
            shadowColor: '#22d3ee', shadowBlur: 10
          },
          emphasis: { itemStyle: { color: '#10b981' } },
          label: { show: true, position: 'right', color: '#93c5fd' }
        }]
      });
    }
    renderTop10();
    setInterval(() => {
      const idx = Math.floor(Math.random() * valuesTop10.length);
      valuesTop10[idx] = Math.floor(50 + Math.random() * 150);
      renderTop10();
    }, 3000);
    window.addEventListener('resize', () => top10Chart.resize());
    top10Chart.on('click', (p) => { /* TODO: 点击穿透详情 */ });

    // 骨架屏：初始化完成后隐藏（如有）
    const skeleton = document.getElementById('skeleton-overlay');
    setTimeout(() => { if (skeleton) { skeleton.style.opacity = '0'; setTimeout(() => skeleton.style.display = 'none', 400); } }, 1200);

    // 底部“手动清理”按钮交互（示例双确认）
    document.getElementById('btnClean')?.addEventListener('click', () => {
      if (!confirm('确认手动清理历史数据吗？')) return;
      setTimeout(() => alert('已提交清理任务（示例），完成后会反馈。'), 200);
    });
  </script>
  <script>
    // ========== 科技感交互效果 ==========
    const DEBUG_MENU = false; // 关闭菜单调试，避免影响导航

    // 数字雨背景效果
    function createMatrixRain() {
      const container = document.body;
      const columns = Math.floor(window.innerWidth / 20);
      const drops = new Array(columns).fill(1);

      function createDrop() {
        const drop = document.createElement('div');
        drop.className = 'matrix-rain';
        drop.style.left = Math.random() * 100 + '%';
        drop.style.animationDuration = (Math.random() * 3 + 2) + 's';
        drop.style.animationDelay = Math.random() * 2 + 's';
        drop.textContent = Math.random() > 0.5 ? '1' : '0';
        container.appendChild(drop);

        setTimeout(() => drop.remove(), 5000);
      }

      // 每隔一段时间创建新的数字雨
      setInterval(createDrop, 200);
    }

    // 数据卡片加载效果
    function addLoadingEffect() {
      const cards = document.querySelectorAll('.card.datav');
      cards.forEach((card, index) => {
        card.classList.add('loading');
        setTimeout(() => {
          card.classList.remove('loading');
        }, 500 + index * 100);
      });
    }

    // 实时数据更新效果
    function simulateDataUpdate() {
      const values = document.querySelectorAll('.card.datav .value');
      values.forEach(value => {
        const originalValue = value.textContent;
        // 随机触发数据更新效果
        setInterval(() => {
          if (Math.random() > 0.7) {
            value.style.transform = 'scale(1.1)';
            value.style.color = '#35e3ff';
            setTimeout(() => {
              value.style.transform = 'scale(1)';
              value.style.color = '';
            }, 300);
          }
        }, 3000 + Math.random() * 4000);
      });
    }

    // 鼠标跟随光效
    function createMouseGlow() {
      const glow = document.createElement('div');
      glow.style.cssText = `
        position: fixed; width: 200px; height: 200px; border-radius: 50%;
        background: radial-gradient(circle, rgba(53,227,255,0.1) 0%, transparent 70%);
        pointer-events: none; z-index: 3; transform: translate(-50%, -50%);
        transition: opacity 0.3s ease;
      `;
      document.body.appendChild(glow);

      document.addEventListener('mousemove', (e) => {
        glow.style.left = e.clientX + 'px';
        glow.style.top = e.clientY + 'px';
      });

      // 鼠标离开时淡出
      document.addEventListener('mouseleave', () => {
        glow.style.opacity = '0';
      });

      document.addEventListener('mouseenter', () => {
        glow.style.opacity = '1';
      });
    }

    // 扫描线随机触发
    function randomScanEffect() {
      const cards = document.querySelectorAll('.card.datav');
      setInterval(() => {
        const randomCard = cards[Math.floor(Math.random() * cards.length)];
        randomCard.style.animation = 'none';
        setTimeout(() => {
          randomCard.style.animation = '';
        }, 10);
      }, 5000);
    }

    // 故障艺术效果
    function triggerGlitchEffect() {
      const title = document.querySelector('.datav-title');
      setInterval(() => {
        if (Math.random() > 0.9) {
          title.style.animation = 'glitch 0.3s ease-in-out';
          setTimeout(() => {
            title.style.animation = '';
          }, 300);
        }
      }, 4000);
    }

    // 粒子连线效果
    function createParticleConnections() {
      const canvas = document.createElement('canvas');
      canvas.style.cssText = `
        position: fixed; top: 0; left: 0; width: 100%; height: 100%;
        pointer-events: none; z-index: -1; opacity: 0.3;
      `;
      document.body.appendChild(canvas);

      const ctx = canvas.getContext('2d');
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      const particles = [];
      const particleCount = 50;

      class Particle {
        constructor() {
          this.x = Math.random() * canvas.width;
          this.y = Math.random() * canvas.height;
          this.vx = (Math.random() - 0.5) * 0.5;
          this.vy = (Math.random() - 0.5) * 0.5;
          this.radius = Math.random() * 2 + 1;
        }

        update() {
          this.x += this.vx;
          this.y += this.vy;

          if (this.x < 0 || this.x > canvas.width) this.vx = -this.vx;
          if (this.y < 0 || this.y > canvas.height) this.vy = -this.vy;
        }

        draw() {
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
          ctx.fillStyle = 'rgba(53,227,255,0.8)';
          ctx.fill();
        }
      }

      for (let i = 0; i < particleCount; i++) {
        particles.push(new Particle());
      }

      function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        particles.forEach(particle => {
          particle.update();
          particle.draw();
        });

        // 绘制连线
        particles.forEach((p1, i) => {
          particles.slice(i + 1).forEach(p2 => {
            const distance = Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
            if (distance < 150) {
              ctx.beginPath();
              ctx.moveTo(p1.x, p1.y);
              ctx.lineTo(p2.x, p2.y);
              ctx.strokeStyle = `rgba(53,227,255,${0.2 * (1 - distance / 150)})`;
              ctx.stroke();
            }
          });
        });

        requestAnimationFrame(animate);
      }

      animate();

      window.addEventListener('resize', () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
      });
    }

    // 性能检测和用户偏好适配
    function shouldUseReducedMotion() {
      return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    }

    function isLowPerformanceDevice() {
      // 简单的性能检测
      const canvas = document.createElement('canvas');
      const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
      return !gl || navigator.hardwareConcurrency < 4;
    }

    // 初始化所有科技效果
    function initTechEffects() {
      const reducedMotion = shouldUseReducedMotion();
      const lowPerf = isLowPerformanceDevice();

      // 基础效果（始终启用）
      addLoadingEffect();
      simulateDataUpdate();

      if (!reducedMotion && !lowPerf) {
        // 高性能设备启用全部效果
        createMatrixRain();
        createMouseGlow();
        randomScanEffect();
        triggerGlitchEffect();

        // 延迟加载粒子效果避免影响首屏渲染
        setTimeout(createParticleConnections, 1000);
      } else if (!reducedMotion) {
        // 中等性能设备启用部分效果
        createMouseGlow();
        randomScanEffect();
      }

      // 显示性能状态（开发环境）
      if (lowPerf) {
        console.log('检测到低性能设备，已启用优化模式');
      }
      if (reducedMotion) {
        console.log('检测到减少动画偏好，已禁用部分动画效果');
      }
    }

    // 菜单功能测试和调试
    function debugMenuFunctionality() {
      const menuLinks = document.querySelectorAll('.menu a, .tree-link');
      console.log(`发现 ${menuLinks.length} 个菜单链接`);

      menuLinks.forEach((link, index) => {
        // 添加调试样式，确保链接可点击
        link.style.position = 'relative';
        link.style.zIndex = '10';

        // 添加点击事件监听器用于调试
        link.addEventListener('click', function(e) {
          console.log(`菜单链接 ${index + 1} 被点击:`, this.href, this.textContent);

          // 测试导航功能
          if (this.href && !this.href.includes('javascript:')) {
            console.log(`准备导航到: ${this.href}`);
            // 注释掉实际的页面跳转，只测试点击功能
            // window.location.href = this.href;
          } else {
            console.log('这是一个树状菜单链接或特殊链接');
          }
        });

        // 添加悬停测试
        link.addEventListener('mouseenter', function() {
          console.log(`悬停在菜单: ${this.textContent}`);
        });

        link.addEventListener('mouseleave', function() {
          console.log(`离开菜单: ${this.textContent}`);
        });
      });

      // 测试树状菜单展开/折叠功能
      const treeHeader = document.querySelector('.tree-header');
      if (treeHeader) {
        console.log('找到树状菜单头部');
        treeHeader.addEventListener('click', function() {
          console.log('树状菜单被点击，当前状态:', this.parentElement.classList.contains('expanded') ? '展开' : '折叠');
        });
      } else {
        console.log('未找到树状菜单头部');
      }
    }

  // 特效开关控制
    let effectsEnabled = true;
    const toggleBtn = document.getElementById('toggleEffects');

    function toggleEffects() {
      effectsEnabled = !effectsEnabled;
      document.body.classList.toggle('tech-effects-disabled');
      toggleBtn.classList.toggle('active');

      if (effectsEnabled) {
        // 重新启用效果
        initTechEffects();
      } else {
        // 清理动态创建的元素
        document.querySelectorAll('.matrix-rain, canvas').forEach(el => el.remove());
      }
    }

    toggleBtn?.addEventListener('click', toggleEffects);
    toggleBtn?.classList.add('active'); // 默认开启状态

    // 简单的菜单点击测试
    function simpleMenuTest() {
      console.log('=== 开始菜单功能简单测试 ===');
      const menu = document.querySelector('.menu');
      if (!menu) { console.log('❌ 未找到菜单容器'); return; }
      console.log('✅ 找到菜单容器');
      const links = menu.querySelectorAll('a');
      console.log(`✅ 找到 ${links.length} 个菜单链接`);
      links.forEach((link, index) => {
        link.style.pointerEvents = 'auto';
        link.style.cursor = 'pointer';
        // 仅记录点击，不阻止默认行为
        link.addEventListener('click', () => {
          console.log(`🔗 菜单项 ${index + 1} 被点击: ${link.textContent} -> ${link.href}`);
        });
      });
      console.log('=== 菜单功能测试完成 ===');
    }

  // 页面加载完成后初始化
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => {
        initTechEffects();
        debugMenuFunctionality();
        setTimeout(simpleMenuTest, 1000);
      });
    } else {
      initTechEffects();
      debugMenuFunctionality();
      setTimeout(simpleMenuTest, 1000);
    }

    // 树状菜单展开/折叠
    const th = document.querySelector('.tree-header');
    if (th) th.addEventListener('click', () => th.parentElement.classList.toggle('expanded'));

    // 在线/总数 数据拉取并渲染（容错）
    const IS_FILE_ENV = location.protocol === 'file:';
    const ONLINE_API = {
      crypto: '/api/crypto/devices/online',
      security: '/api/security/devices/online',
    };
    async function fetchOnline(url) {
      const res = await fetch(url, { headers: { 'Accept': 'application/json' } });
      if (!res.ok) throw new Error('HTTP '+res.status);
      let data = await res.json().catch(() => null);
      // 兼容返回数组：[{status:'online'}, ...]
      if (Array.isArray(data)) {
        const total = data.length;
        const online = data.filter(d => (d.status||'').toLowerCase() === 'online' || d.online === true || d.state === '在线').length;
        return { online, total };
      }
      // 兼容对象：{online:12,total:12} 或 {onlineCount:12,totalCount:12}
      if (data && typeof data === 'object') {
        const online = data.online ?? data.onlineCount ?? data.countOnline ?? 0;
        const total = data.total ?? data.totalCount ?? data.countTotal ?? (data.devices?.length||0);
        return { online, total };
      }
      throw new Error('Unexpected response');
    }
    function renderOnline(id, online, total) {
      const el = document.getElementById(id);
      if (!el) return;
      el.textContent = `${online}/${total} 台`;
    }
    // 安全的API调用，避免CORS错误影响页面功能
    function safeFetchOnline(url, fallbackData) {
      if (IS_FILE_ENV) {
        console.info('file:// 环境，直接使用回退数据:', url);
        return Promise.resolve(fallbackData);
      }
      return fetchOnline(url).catch(e => {
        console.warn(`API请求失败，使用回退数据: ${url}`, e);
        return fallbackData;
      });
    }

    (async () => {
      // 加密设备
      const cryptoData = await safeFetchOnline(ONLINE_API.crypto, { online: 12, total: 12 });
      renderOnline('metric-crypto-online', cryptoData.online, cryptoData.total);

      // 安全设备
      const securityData = await safeFetchOnline(ONLINE_API.security, { online: 8, total: 8 });
      renderOnline('metric-security-online', securityData.online, securityData.total);
    })();
  </script>
<div id="skeleton-overlay"></div>
</body>
 </html>


<video id="bg-video" class="bg-video" src="assets/jimeng-2025-10-22-6419.mp4" autoplay muted loop playsinline preload="auto" aria-hidden="true"></video>
